home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / disk-man / userflop.2 / userflop / userfloppy0.2 / usermount.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-28  |  9.2 KB  |  389 lines

  1. /* Usermount.c : build over the Peter Orbaek mount, just only cutting here 
  2.    and there by Romano Giannetti. It permits to normal users mount devices
  3.    the superuser list in /etc/ufstab. It admit multiple entry with different 
  4.    fs-type and equal device and directory (see the exemple for /floppy) 
  5. */
  6.  
  7. /* 
  8.     mount.c - A better mount command for Linux 0.99-patchlevel 8 or later.
  9.     by Peter Orbaek <poe@daimi.aau.dk>
  10.  
  11.     Copyright (C) 1992,93 Peter Orbaek.
  12.  
  13.     This program is free software; you can redistribute it and/or modify
  14.     it under the terms of the GNU General Public License as published by
  15.     the Free Software Foundation; either version 2 of the License, or
  16.     (at your option) any later version.
  17.  
  18.     This program is distributed in the hope that it will be useful,
  19.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.     GNU General Public License for more details.
  22.  
  23.     You should have received a copy of the GNU General Public License
  24.     along with this program; if not, write to the Free Software
  25.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26. */
  27.  
  28. #define _BSD_SOURCE
  29. #define _POSIX_SOURCE
  30. #include <stdio.h>
  31. #include <errno.h>
  32. #include <unistd.h>
  33. #include <fcntl.h>
  34. #include <mntent.h>
  35. #include <getopt.h>
  36. #include <string.h>
  37. #include <errno.h>
  38. #include <sys/stat.h>
  39. #include <sys/mount.h>
  40. #include <sys/types.h>
  41.  
  42.  
  43. /*#define _LINUX_TYPES_H*/
  44. #include <linux/fs.h>
  45.  
  46. /* these really should be defined in <mntent.h>. */
  47. #define MNTOPT_NODEV    "nodev"
  48. #define MNTOPT_NOEXEC   "noexec"
  49. #define MNTOPT_SYNC     "sync"
  50.  
  51. #ifndef __STDC__
  52. #error Error: This program requires ANSI C to compile
  53. #endif
  54.  
  55. #define MTAB_FILE MOUNTED
  56. #define LOCK_FILE "/etc/mtab~"
  57.  
  58. #define UFSTAB "/etc/ufstab"
  59.  
  60. int opt_mountall = 0;
  61. int opt_print    = 0;
  62. int opt_verbose  = 0;
  63. int opt_std      = 0;
  64. int opt_usermount= 0;
  65. int opt_fakemtab = 0;
  66. int opt_nomtab   = 0;
  67. int opt_type     = 0;
  68.  
  69. char opt_nostd[200];
  70. char mntoptions[200] = "defaults";
  71.  
  72. char mnttype[MNTMAXSTR] = "";
  73. char *mntdev = NULL, *mntdir = NULL;
  74. char mntdevbuf[MNTMAXSTR];
  75.  
  76. void usage(), process_options(char *opts);
  77. void err(char *str);
  78. void print_mtab(char *);
  79. int do_mount(struct mntent *);
  80. int lock_mtab();
  81. void unlock_mtab();
  82. void print_mntent(struct mntent *);
  83.  
  84. void usage()
  85. {
  86.     fprintf(stderr,
  87.         "Usage: usermount [-fnprv] [-t type] [-o options] [[dev] dir]\n");
  88.  
  89.     err(NULL);
  90. }
  91.  
  92. int main(int argc, char *argv[])
  93. {
  94.     char c;
  95.  
  96.     /* parse options */
  97.  
  98.     while((c = getopt(argc, argv, "fnpt:rvo:")) != EOF) {
  99.     switch(c) {
  100.       case 'p':
  101.         opt_print = 1;
  102.         break;
  103.       case 't':
  104.         strncpy(mnttype, optarg, MNTMAXSTR-1);
  105.         opt_type=1;
  106.         break;
  107.       case 'r':
  108.         if(mntoptions[0] != '\0') strcat(mntoptions, ",");
  109.         strcat(mntoptions, "ro");
  110.         break;
  111.       case 'v':
  112.         opt_verbose = 1;
  113.         break;
  114.       case 'o':
  115.         strncpy(mntoptions, optarg, sizeof(mntoptions)-1);
  116.         break;
  117.       case 'f':
  118.         opt_fakemtab = 1;
  119.         break;
  120.       case 'n':
  121.         opt_nomtab = 1;
  122.         break;
  123.       default:
  124.         usage();
  125.     }
  126.     }
  127.  
  128.     opt_usermount = 1; /* RGtti: only usermount */
  129.  
  130.     if(optind < argc) {
  131.     mntdev = argv[optind++];
  132.     if(optind >= argc) {
  133.         char *filename = UFSTAB;
  134.         FILE *fstab;
  135.         struct mntent *mp;
  136.         
  137.  
  138.         /* only a mount-point was given, look up device in fstab */
  139.         mntdir = mntdev; mntdev = NULL;
  140.  
  141.         if(!(fstab = setmntent(filename, "r"))) err(filename);
  142.         while((mp = getmntent(fstab))) {
  143.         if( (!strcmp(mntdir, mp->mnt_dir)) && 
  144.                     (!strcmp(mnttype, mp->mnt_type) || !opt_type) ) {
  145.             strncpy(mntdevbuf, mp->mnt_fsname, sizeof(mntdevbuf)-1);
  146.             mntdev = mntdevbuf;
  147.             break;
  148.         } else if( (!strcmp(mntdir, mp->mnt_fsname)) &&
  149.                            (!strcmp(mnttype, mp->mnt_type) || !opt_type)) {
  150.             strncpy(mntdevbuf, mp->mnt_dir, sizeof(mntdevbuf)-1);
  151.             mntdev = mntdir;
  152.             mntdir = mntdevbuf;
  153.         }
  154.         }
  155.         endmntent(fstab);
  156.  
  157.         if(!mntdev) {
  158.         fprintf(stderr, "mount: Don't know what to mount on %s\n",
  159.             mntdir);
  160.         err(NULL);
  161.         }
  162.     } else mntdir = argv[optind];
  163.  
  164.     } else if(argc == 1) {
  165.     /* with no args, just print mtab */
  166.     print_mtab(MTAB_FILE);
  167.     unlock_mtab();
  168.     exit(0);
  169.     }
  170.  
  171.     /* done with the arguments, now do some work */
  172.  
  173.     if(geteuid()) {
  174.     fprintf(stderr, "usermount: I have to be installed setuid root!.\n");
  175.     err(NULL);
  176.     }
  177.  
  178.     /* check for lock */
  179.     if(!lock_mtab()) {
  180.     /* don't use err() for this */
  181.     fprintf(stderr, "usermount: A lock-file exists, mount denied.\n");
  182.     exit(1);
  183.     }
  184.  
  185.     if(mntdir) {
  186.     struct mntent mnt;
  187.  
  188.     if(opt_usermount) {
  189.         FILE *fstab;
  190.         struct mntent *mp;
  191.         int flag = 0;
  192.  
  193.         if(!(fstab = setmntent(UFSTAB, "r"))) err(UFSTAB);
  194.         while((mp = getmntent(fstab))) {
  195.         if(!strcmp(mntdev, mp->mnt_fsname) 
  196.            && !strcmp(mntdir, mp->mnt_dir)
  197.                    && (!strcmp(mnttype, mp->mnt_type) || !opt_type) ) {
  198.             flag = 1;
  199.             strncpy(mntoptions, mp->mnt_opts, sizeof(mntoptions)-1);
  200.             strncpy(mnttype, mp->mnt_type, sizeof(mnttype)-1);
  201.             break;
  202.         }
  203.         }
  204.         endmntent(fstab);
  205.         if(!flag) {
  206.         fprintf(stderr, "usermount: Can't usermount %s.\n", mntdir);
  207.         err(NULL);
  208.         }
  209.     }
  210.  
  211.     mnt.mnt_type   = mnttype;
  212.     mnt.mnt_fsname = mntdev;
  213.     mnt.mnt_dir    = mntdir;
  214.     mnt.mnt_opts   = mntoptions;
  215.     mnt.mnt_freq   = 0;
  216.     mnt.mnt_passno = 0;
  217.  
  218.     if(!do_mount(&mnt)) {
  219.         unlock_mtab();
  220.         exit(1);
  221.     }
  222.  
  223.     /* Now set the uid, gid of the mount-point to the user */
  224.  
  225.     chown(mntdir,getuid(),getgid());
  226.     }
  227.  
  228.     unlock_mtab();
  229.  
  230.     exit(0);
  231. }
  232.  
  233. int lock_mtab()
  234. {
  235.     int fd;
  236.  
  237.     if((fd = open(LOCK_FILE, O_WRONLY | O_CREAT | O_EXCL, 0744)) < 0) return 0;
  238.     close(fd);
  239.     return 1;
  240. }
  241.  
  242. void unlock_mtab()
  243. {
  244.     unlink(LOCK_FILE);
  245. }
  246.  
  247. int do_mount(struct mntent *mp)
  248. {
  249.     struct stat s;
  250.     FILE *mtab;
  251.  
  252.     if(!mp->mnt_type || !mp->mnt_type[0]) mp->mnt_type = "minix";
  253.     
  254.     if(!opt_fakemtab) {
  255.     /* check the directory */
  256.     if(stat(mp->mnt_dir, &s) < 0) {
  257.         if(errno == ENOENT || errno == ESRCH) {
  258.         if(mkdir(mp->mnt_dir, 0755) < 0) {
  259.             fprintf(stderr, "usermount: mkdir(%s) failed.\n", mp->mnt_dir);
  260.             return 0;
  261.         }
  262.  
  263.         if(opt_verbose) 
  264.           fprintf(stderr, "Made directory: %s\n", mp->mnt_dir);
  265.         
  266.         } else {
  267.         fprintf(stderr, "usermount: stat(%s) failed.\n", mp->mnt_dir);
  268.         return 0;
  269.         }
  270.  
  271.     } else if(!S_ISDIR(s.st_mode)) {
  272.         fprintf(stderr, "usermount: %s already exists, and isn't a directory.\n",
  273.             mp->mnt_dir);
  274.         return 0;
  275.     }
  276.  
  277.     process_options(mp->mnt_opts);
  278.  
  279. #if 0
  280.     printf("usermount(%s,%s,%s,%x,%s)\n", mp->mnt_fsname, mp->mnt_dir,
  281.            mp->mnt_type, opt_std, opt_nostd);
  282. #endif
  283.  
  284.     if(strcmp(mp->mnt_dir, "/") == 0) {
  285.         if(opt_verbose)
  286.           fprintf(stderr, "usermount: root already mounted by kernel\n");
  287.     } else {
  288.         if(strcmp(mp->mnt_type, MNTTYPE_IGNORE) == 0) {
  289.         if(opt_verbose)
  290.           fprintf(stderr, "usermount: ignored %s\n", mp->mnt_fsname);
  291.         return 1;
  292.         }
  293.  
  294.         if(strcmp(mp->mnt_type, MNTTYPE_SWAP) == 0) {
  295.         fprintf(stderr,"usermount: normal user cannot add swap\n");
  296.         return 1;
  297.         } else {
  298.         if(mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
  299.              0xc0ed0000|opt_std, opt_nostd) < 0) {
  300.             fprintf(stderr, "usermount: mount(%s,%s) failed: %s\n", 
  301.                 mp->mnt_fsname, mp->mnt_dir, strerror(errno));
  302.             return 0;
  303.         }
  304.         if(opt_verbose)
  305.           fprintf(stderr, "Mounted %s on %s.\n", mp->mnt_fsname, 
  306.               mp->mnt_dir);
  307.         }
  308.     }
  309.     } /* if(!opt_fakemtab) */
  310.  
  311.     if(!opt_nomtab) {
  312.     if(!(mtab = setmntent(MTAB_FILE, "a"))) {
  313.         fprintf(stderr, "usermount: open(%s) failed.\n", MTAB_FILE);
  314.         return 1;
  315.     }
  316.     addmntent(mtab, mp);
  317.     
  318.     endmntent(mtab);
  319.     }
  320.  
  321.     return 1;
  322. }
  323.  
  324. void err(char *str)
  325. {
  326.     if(str) fprintf(stderr, "usermount: %s: %s\n", str, strerror(errno));
  327.  
  328.     if(access(LOCK_FILE, 0) == 0) unlink(LOCK_FILE);
  329.     exit(1);
  330. }
  331.  
  332. void print_mntent(struct mntent *mp)
  333. {
  334.     printf("%s\t%s\t%s\t%s\t%d\t%d\n", mp->mnt_fsname, mp->mnt_dir,
  335.        mp->mnt_type, (mp->mnt_opts[0] == 0) ? "defaults" : mp->mnt_opts, 
  336.        mp->mnt_freq, mp->mnt_passno);
  337. }
  338.  
  339. void print_mtab(char *filename)
  340. {
  341.     FILE *mf;
  342.     struct mntent *mp;
  343.  
  344.     if(!((mf = setmntent(filename, "r")))) err(filename);
  345.     while((mp = getmntent(mf))) print_mntent(mp);
  346.     endmntent(mf);
  347. }
  348.  
  349.  
  350. void process_options(char *opts)
  351. {
  352.     /* opts is a comma-separated list of options */
  353.     char opt[MNTMAXSTR];
  354.     char *p;
  355.  
  356.     opt_nostd[0] = '\0';
  357.     opt_std = 0;
  358.  
  359.     while(opts && *opts) {
  360.     for(p = opt; *opts && *opts != ','; *p++ = *opts++);
  361.     *p = '\0';
  362.     if(*opts == ',') opts++;
  363.  
  364.     /* standard options, should be supported by all filesystems */
  365.     if(!strcmp(opt, MNTOPT_DEFAULTS)) {
  366.         if(opt_usermount)
  367.           opt_std = MS_NOSUID|MS_NODEV|MS_NODEV|MS_NOEXEC;
  368.         else
  369.           opt_std = 0;
  370.     }
  371.     else if(!strcmp(opt, MNTOPT_RO))     opt_std |= MS_RDONLY;
  372.     else if(!strcmp(opt, MNTOPT_RW))     opt_std &= ~MS_RDONLY;
  373.     else if(!strcmp(opt, MNTOPT_SUID))   opt_std &= ~MS_NOSUID;
  374.     else if(!strcmp(opt, MNTOPT_NOSUID)) opt_std |= MS_NOSUID;
  375.     else if(!strcmp(opt, MNTOPT_NODEV))  opt_std |= MS_NODEV;
  376.     else if(!strcmp(opt, MNTOPT_NOEXEC)) opt_std |= MS_NOEXEC;
  377.     else if(!strcmp(opt, MNTOPT_SYNC))   opt_std |= MS_SYNC;
  378.     else {
  379.         /* non-standard options are put in a comma-sep. string */
  380.         strcat(opt_nostd, opt);
  381.         strcat(opt_nostd, ",");
  382.     }
  383.     }
  384.  
  385.     if(opt_nostd[0])
  386.       opt_nostd[strlen(opt_nostd)-1] = '\0';
  387.     
  388. }
  389.